<?php

require_once 'SpecHelper.php';
require_once 'PHPMock.php';
require_once '_helpers/Album.php';

class DescribePHPMockMethodExpectations extends PHPSpec_Context
{
    
    protected $_mock = null;
    
    public function before()
    {
        $this->_mock = PHPMock::mock('PHPMockSpec_Album');
    }

    /**public function itShouldExpectEachMethodExactlyOnceUnlessOtherwiseSpecified()
    {
        $this->_mock->shouldReceive('getName');
        $this->_mock->getName();
        $this->spec($this->_mock->verify())->should->beTrue();
    }
    
    public function itShouldThrowDefaultExceptionIfMethodCallCountIsUnexpected()
    {
        $this->_mock->shouldReceive('getName'); // once only by default
        $this->_mock->getName();
        $this->_mock->getName();
        try {
            $this->_mock->verify();
            $this->fail();
        } catch (PHPMock_Exception $e) {
        }
    }
    
    public function itShouldExpectNumberOfMethodsInTimesTerm()
    {
        $this->_mock->shouldReceive('getName')->times(5);
        for ($i=0; $i <= 4; $i++) {
            $this->_mock->getName();
        }
        $this->spec($this->_mock->verify())->should->beTrue();
    }
    
    public function itShouldReturnSelfFromTimesTermInvocation()
    {
    	$object = $this->_mock->shouldReceive('getName')->times(1);
    	$this->spec($object)->should->beAnInstanceOf('PHPMock_Expectation');
    }
    
    public function itShouldSetReturnValueInTermsAndDefaultToReturningValueForAllCalls()
    {
    	$this->_mock->shouldReceive('getName')->andReturn('Joe');
    	$this->_mock->getName();
    	$this->spec($this->_mock->getName())->should->be('Joe');
    }
    
    public function itShouldReturnValuesInOrderOfSettingButReturnLastValueRemainingOnOtherCalls()
    {
        $this->_mock->shouldReceive('getName')->andReturn('Joe', 'Paddy', 'Travis');
        for ($i=0; $i <= 5; $i++) {
            $this->_mock->getName();
        }
        $this->spec($this->_mock->getName())->should->be('Travis');
    }
    
    public function itShouldReturnSelfFromReturnTermInvocation()
    {
        $object = $this->_mock->shouldReceive('getName')->times(1)->andReturn('Joe');
        $this->spec($object)->should->beAnInstanceOf('PHPMock_Expectation');
    }
    
    public function itShouldSetExpectedArgUsingWithTerm()
    {
    	$this->_mock->shouldReceive('setName')->with('Black Album');
    	$this->_mock->setName('Black Album');
    	try {
    	    $this->_mock->verify();
    	} catch (PHPMock_Exception $e) {
    	    $this->fail($e->getMessage());
    	}
    }**/

    public function itShouldThrowExceptionIfExpectedParameterNotUsedFromWithTerm()
    {
    	$this->_mock->shouldReceive('setName')->with('Black Album');
    	$this->_mock->setName('Black');
    	try {
    	    $this->_mock->verify();
            $this->fail();
    	} catch (PHPMock_Exception $e) {
    	}
    }

    /**public function itShouldSetExpectedMultipleArgsUsingWithTerm()
    {
    	$this->_mock->shouldReceive('setTerms')->with('album', 'music');
    	$this->_mock->setTerms('album', 'music');
    	try {
    	    $this->_mock->verify();
    	} catch (PHPMock_Exception $e) {
    	    $this->fail($e->getMessage());
    	}
    }

    public function itShouldSetExpectedMultipleArgsMatchingRegexUsingWithTerm()
    {
    	$this->_mock->shouldReceive('setTerms')->with("/\d/", "/^php/");
    	$this->_mock->setTerms('2', 'php5');
    	//try {
    	    $this->_mock->verify();
    	//} catch (PHPMock_Exception $e) {
    	//    $this->fail($e->getMessage());
    	//}
    }
    
    public function itShouldReturnSelfFromWithTermInvocation()
    {
        $object = $this->_mock->shouldReceive('setName')->times(1)->with('Joe');
        $this->spec($object)->should->beAnInstanceOf('PHPMock_Expectation');
    }

    public function itShouldAllowNoCallsForZeroormoretimesTerm()
    {
        $this->_mock->shouldReceive('getName')->zeroOrMoreTimes();
        $this->spec($this->_mock->verify())->should->beTrue();
    }

    public function itShouldAllowOneCallWithOnceTerm()
    {
        $this->_mock->shouldReceive('getName')->once();
        $this->_mock->getName();
        $this->spec($this->_mock->verify())->should->beTrue();
    }

    public function itShouldThrowExceptionIfLessThanOnceUsingOnceTern()
    {
        $this->_mock->shouldReceive('getName')->once();
        try {
            $this->_mock->verify();
            $this->fail();
        } catch(PHPMock_Exception $e) {
        }
    }

    public function itShouldThrowExceptionIfGreaterThanOnceUsingOnceTerm()
    {
        $this->_mock->shouldReceive('getName')->once();
        $this->_mock->getName();
        $this->_mock->getName();
        try {
            $this->_mock->verify();
            $this->fail();
        } catch(PHPMock_Exception $e) {
        }
    }

    public function itShouldReturnSelfInstanceFromOnceTerm()
    {
        $object = $this->_mock->shouldReceive('getName')->once();
        $this->spec($object)->should->beAnInstanceOf('PHPMock_Expectation');
    }

    public function itShouldAllowTwoCallsWithTwiceTerm()
    {
        $this->_mock->shouldReceive('getName')->twice();
        $this->_mock->getName();
        $this->_mock->getName();
        $this->spec($this->_mock->verify())->should->beTrue();
    }

    public function itShouldThrowExceptionIfLessThanTwiceUsingTwiceTerm()
    {
        $this->_mock->shouldReceive('getName')->twice();
        $this->_mock->getName();
        try {
            $this->_mock->verify();
            $this->fail();
        } catch(PHPMock_Exception $e) {
        }
    }

    public function itShouldThrowExceptionIfGreaterThanTwiceUsingTwiceTerm()
    {
        $this->_mock->shouldReceive('getName')->once();
        $this->_mock->getName();
        $this->_mock->getName();
        $this->_mock->getName();
        try {
            $this->_mock->verify();
            $this->fail();
        } catch(PHPMock_Exception $e) {
        }
    }

    public function itShouldReturnSelfInstanceFromTwiceTerm()
    {
        $object = $this->_mock->shouldReceive('getName')->twice();
        $this->spec($object)->should->beAnInstanceOf('PHPMock_Expectation');
    }

    public function itShouldAllowNoCallsWithNeverTerm()
    {
        $this->_mock->shouldReceive('getName')->never();
        $this->spec($this->_mock->verify())->should->beTrue();
    }

    public function itShouldThrowExceptionIfAnyCallAfterNeverTerm()
    {
        $this->_mock->shouldReceive('getName')->never();
        $this->_mock->getName();
        try {
            $this->_mock->verify();
            $this->fail();
        } catch(PHPMock_Exception $e) {
        }
    }

    public function itShouldReturnSelfInstanceFromNeverTerm()
    {
        $object = $this->_mock->shouldReceive('getName')->never();
        $this->spec($object)->should->beAnInstanceOf('PHPMock_Expectation');
    }

    public function itShouldAllowAnyCallsForZeroormoretimesTerm()
    {
        $this->_mock->shouldReceive('getName')->zeroOrMoreTimes();
        for ($i=0;$i<=4;$i++) {
            $this->_mock->getName();
        }
        $this->spec($this->_mock->verify())->should->beTrue();
    }

    public function itShouldAllowZeroCallsForZeroormoretimesTerm()
    {
        $this->_mock->shouldReceive('getName')->zeroOrMoreTimes();
        $this->spec($this->_mock->verify())->should->beTrue();
    }

    public function itShouldReturnSelfInstanceFromZeroormoretimesTerm()
    {
        $object = $this->_mock->shouldReceive('getName')->zeroOrMoreTimes();
        $this->spec($object)->should->beAnInstanceOf('PHPMock_Expectation');
    }

    public function itShouldSetTimesMinimumWithOnceUsingAtleastTerm()
    {
        $this->_mock->shouldReceive('getName')->atLeast()->once();
        $this->_mock->getName();
        $this->spec($this->_mock->verify())->should->beTrue();
    }

    public function itShouldSetTimesMinimumWithTimesUsingAtleastTerm()
    {
        $this->_mock->shouldReceive('getName')->atLeast()->times(2);
        $this->_mock->getName();
        $this->_mock->getName();
        $this->_mock->getName();
        $this->spec($this->_mock->verify())->should->beTrue();
    }

    public function itShouldThrowExceptionIfLessThanMinimumUsingAtleastTerm()
    {
        $this->_mock->shouldReceive('getName')->atLeast()->twice();
        $this->_mock->getName();
        try {
            $this->_mock->verify();
            $this->fail();
        } catch(PHPMock_Exception $e) {
        }
    }

    public function itShouldReturnSelfInstanceFromAtleastTerm()
    {
        $object = $this->_mock->shouldReceive('getName')->atLeast();
        $this->spec($object)->should->beAnInstanceOf('PHPMock_Expectation');
    }

    public function itShouldSetTimesMaximumWithOnceUsingAtmostTerm()
    {
        $this->_mock->shouldReceive('getName')->atMost()->once();
        $this->_mock->getName();
        $this->spec($this->_mock->verify())->should->beTrue();
    }

    public function itShouldSetTimesMaximumWithTimesUsingAtmostTerm()
    {
        $this->_mock->shouldReceive('getName')->atMost()->times(2);
        $this->_mock->getName();
        $this->spec($this->_mock->verify())->should->beTrue();
    }

    public function itShouldThrowExceptionIfMoreThanTwiceUsingTwiceTerm()
    {
        $this->_mock->shouldReceive('getName')->twice();
        $this->_mock->getName();
        $this->_mock->getName();
        $this->_mock->getName();
        try {
            $this->_mock->verify();
            $this->fail();
        } catch(PHPMock_Exception $e) {
        }
    }

    public function itShouldReturnSelfInstanceFromAtmostTerm()
    {
        $object = $this->_mock->shouldReceive('getName')->atMost();
        $this->spec($object)->should->beAnInstanceOf('PHPMock_Expectation');
    }

    public function itShouldAllowAnyArgsUsingWithanyargsTerm()
    {
        $this->_mock->shouldReceive('getName')->withAnyArgs()
                    ->andReturn('SomeName');
        $this->spec($this->_mock->getName('x', 'y', 'z'))->should->be('SomeName');
    }

    public function itShouldReturnSelfInstanceFromWithanyargsTerm()
    {
        $object = $this->_mock->shouldReceive('getName')->withAnyArgs();
        $this->spec($object)->should->beAnInstanceOf('PHPMock_Expectation');
    }

    public function itShouldDisallowArgsUsingWithnoargsTerm()
    {
        $this->_mock->shouldReceive('getName')->withNoArgs();
        try {
            $this->_mock->getName('x');
            $this->fail();
        } catch (PHPMock_Exception $e) {
        }
    }

    public function itShouldReturnSelfInstanceFromWithnoargsTerm()
    {
        $object = $this->_mock->shouldReceive('getName')->withNoArgs();
        $this->spec($object)->should->beAnInstanceOf('PHPMock_Expectation');
    }

    public function itShouldObeyOrderingViaSequenceOfOrderedTermCalls()
    {
        $this->_mock->shouldReceive('setName')->with('name')->ordered();
        $this->_mock->shouldReceive('getName')->ordered();
        $this->_mock->setName('name');
        $this->_mock->getName();
        $this->spec($this->_mock->verify())->should->beTrue();
    }

    public function itShouldDisallowMethodCallingIfMethodHasSpecifiedOrder()
    {
        $this->_mock->shouldReceive('getName')->withNoArgs()->ordered();
        $this->_mock->shouldReceive('setName')->once()->withAnyArgs()->ordered();
        try {
            $this->_mock->setName('x');
            $this->fail();
        } catch (PHPMock_Exception $e) {
        }
    }

    public function itShouldAllowMethodCallingOfUnorderedExpectationsInAnyOrder()
    {
        $this->_mock->shouldReceive('getName')->withNoArgs()->ordered();
        $this->_mock->shouldReceive('setName')->once()->withAnyArgs()->ordered();
        $this->_mock->shouldReceive('hasName')->withNoArgs(); // not ordered; call any time
        try {
            $this->_mock->hasName();
            $this->_mock->getName();
            $this->_mock->setName('x');
        } catch (PHPMock_Exception $e) {
            $this->fail();
        }
    }

    public function itShouldReturnSelfInstanceFromOrderedTerm()
    {
        $object = $this->_mock->shouldReceive('getName')->ordered();
        $this->spec($object)->should->beAnInstanceOf('PHPMock_Expectation');
    }

    public function itShouldThrowSpecifiedExceptionUsingAndthrowTerm()
    {
        $this->_mock->shouldReceive('hasName')->andThrow('PHPMockSpec_Album_Exception');
        try {
            $this->_mock->hasName();
            $this->fail();
        } catch (PHPMockSpec_Album_Exception $e) {
            // pass
        } catch (Exception $e) {
            $this->fail();
        }
    }

    public function itShouldThrowSpecifiedExceptionWithMessageUsingAndthrowTerm()
    {
        $this->_mock->shouldReceive('hasName')->andThrow('PHPMockSpec_Album_Exception', 'somemessage');
        try {
            $this->_mock->hasName();
            $this->fail();
        } catch (PHPMockSpec_Album_Exception $e) {
            //$this->spec($e->getMessage())->should->be('somemessage');
        }
    }

    public function itShouldThrowExceptionIfClassPassedToAndthrowTermNotAnException()
    {
        try {
            $this->_mock->shouldReceive('hasName')->andThrow('PHPMockSpec_Album');
            $this->fail();
        } catch (PHPMock_Exception $e) {
        }
    }

    public function itShouldReturnSelfInstanceFromAndthrowTerm()
    {
        $object = $this->_mock->shouldReceive('getName')->andThrow('Exception');
        $this->spec($object)->should->beAnInstanceOf('PHPMock_Expectation');
    }**/

    public function after()
    {
        unset($this->_mock);
    }
    
}